#pragma once

#include <exception>

#include "exports.hpp"




namespace services
{
	class operation_cancelled
		: public std::exception
	{
	public:
	};
	///////////////////////////////////////////////////////////////////////////////////////////////

	/**
	 * A progress_listener acts as an interface between an operation that takes
	 * a long time and something that wants information about the progress of that
	 * operation and/or cancel it.
	 *
	 * A progress_listener can be used in conjunction with a task, for example.
	 * Usually, the operation calls setProgress on the listener, telling it
	 * the current progress. However once cancel has been called, all subsequent calls
	 * to setProgress and setRange throw an operation_cancelled exception, which causes
	 * the operation to quit by callstack-unwinding.
	 * @important In order for this to work, all exceptions of the type operation_cancelled
	 *            must either not be catched, or rethrown, so that the caller of the operation
	 *            can catch it.
	 * @see operation_cancelled
	 */
	class SERVICES_API progress_listener
	{
	public:

		/**
		 * Creates a new progress with the given range.
		 * The current progress is set to min and cancelled to false.
		 */
		progress_listener(int min = 0, int max = 100);



		/**
		 * Cancels the task/operation this listener is attached to.
		 */
		void cancel();

		/**
		 * Tests if the attached task has been cancelled or not.
		 */
		bool cancelled() const;

		/**
		 * Sets the range of the progress to the given one.
		 */
		void setRange(int min, int max);

		/**
		 * Sets the progress of the attached task.
		 * @throws task_cancelled in case the task has been cancelled
		 */
		void setProgress(int progress);

		/**
		 * @returns the current progress of the attached task
		 */
		int current() const;

		/**
		 * @returns the relative progress of the attached task
		 */
		float relative_progress() const;

	private:

		volatile int    m_min;
		volatile int    m_max;
		volatile int    m_progress;
		volatile bool   m_cancel;
	};
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
